<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>xmake</title>
  <link rel="icon" href="/assets/img/favicon.ico">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
  <meta name="description" content="Description">
  <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <link href="//cdn.jsdelivr.net/npm/github-markdown-css@4.0.0/github-markdown.min.css" rel="stylesheet">
  <style>
	.markdown-body {
		box-sizing: border-box;
		min-width: 200px;
		max-width: 980px;
		margin: 0 auto;
		padding: 45px;
	}

	@media (max-width: 767px) {
		.markdown-body {
			padding: 15px;
		}
	}
  </style>
</head>
<body>
<article class="markdown-body">
<h4>This is a mirror page, please see the original page: </h4><a href="https://xmake.io/#/guide/other_features">https://xmake.io/#/guide/other_features</a>
</br>
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CE7I52QU&placement=xmakeio" id="_carbonads_js"></script>
<style>
#carbonads {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu,
  Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif;
}

#carbonads {
  display: flex;
  max-width: 330px;
  background-color: hsl(0, 0%, 98%);
  box-shadow: 0 1px 4px 1px hsla(0, 0%, 0%, .1);
}

#carbonads a {
  color: inherit;
  text-decoration: none;
}

#carbonads a:hover {
  color: inherit;
}

#carbonads span {
  position: relative;
  display: block;
  overflow: hidden;
}

#carbonads .carbon-wrap {
  display: flex;
}

.carbon-img {
  display: block;
  margin: 0;
  line-height: 1;
}

.carbon-img img {
  display: block;
}

.carbon-text {
  font-size: 13px;
  padding: 10px;
  line-height: 1.5;
  text-align: left;
}

.carbon-poweredby {
  display: block;
  padding: 8px 10px;
  background: repeating-linear-gradient(-45deg, transparent, transparent 5px, hsla(0, 0%, 0%, .025) 5px, hsla(0, 0%, 0%, .025) 10px) hsla(203, 11%, 95%, .4);
  text-align: center;
  text-transform: uppercase;
  letter-spacing: .5px;
  font-weight: 600;
  font-size: 9px;
  line-height: 1;
}
</style>
    <h2 id="trybuildingwithanotherbuildsystemtrybuildmode">Try building with another build system (TryBuild Mode)</h2>
<p>xmake v2.3.1 and above directly interface with other third-party build systems. Even if other projects do not use xmake.lua for maintenance, xmake can directly call other build tools to complete the compilation.</p>
<p>Then the user can directly use a third-party build tool to compile, so why use xmake to call it? The main benefits are:</p>
<ol>
<li>Completely consistent behavior, simplifying the compilation process. No matter which other build system is used, you only need to execute the xmake command to compile. Users no longer need to study the different compilation processes of other tools</li>
<li>Docking the configuration environment of <code>xmake config</code>, reuse the platform detection and SDK environment detection of xmake, simplify the platform configuration</li>
<li>Docking cross-compilation environment, even for projects maintained with autotools, you can quickly cross-compile through xmake</li>
</ol>
<p>Build systems currently supported:</p>
<ul>
<li>autotools (support for cross-compiling with xmake)</li>
<li>xcodebuild</li>
<li>cmake (support for cross-compiling with xmake)</li>
<li>make</li>
<li>msbuild</li>
<li>scons</li>
<li>meson</li>
<li>bazel</li>
<li>ndkbuild</li>
<li>ninja</li>
</ul>
<h3 id="automaticallydetectbuildsystemandcompile">Automatically detect build system and compile</h3>
<p>For example, for a project maintained using cmake, executing xmake directly in the project root directory will automatically trigger a detection mechanism, detect CMakeLists.txt, and then prompt the user if cmake is needed to continue compiling.</p>
<pre><code class="lang-bash">$ xmake 
note: CMakeLists.txt found, try building it (pass -y or --confirm=y/n/d to skip confirm)?
please input: y (y/n)
-- Symbol prefix:
-- Configuring done
-- Generating done
-- Build files have been written to:/Users/ruki/Downloads/libpng-1.6.35/build
[  7%] Built target png-fix-itxt
[ 21%] Built target genfiles
[ 81%] Built target png
[ 83%] Built target png_static
...
output to/Users/ruki/Downloads/libpng-1.6.35/build/artifacts
build ok!
</code></pre>
<h3 id="seamlessusingxmakecommand">Seamless using xmake command</h3>
<p>Currently supports common commands such as <code>xmake clean</code>,<code>xmake --rebuild</code> and <code>xmake config</code> to seamlessly interface with third-party systems.</p>
<p>We can directly clean the compiled output files of the cmake maintenance project</p>
<pre><code class="lang-bash">$ xmake clean
$ xmake clean --all
</code></pre>
<p>If you bring <code>--all</code> to perform the cleanup, all files generated by autotools/cmake will be cleared, not only the object files.</p>
<p>The default <code>xmake</code> is docked with incremental build behavior, but we can also force a quick rebuild:</p>
<pre><code class="lang-bash">$ xmake --rebuild
</code></pre>
<h3 id="manuallyswitchthespecifiedbuildsystem">Manually switch the specified build system</h3>
<p>If there are multiple build systems under maintenance in a project, such as the libpng project, which comes with autotools/cmake/makefile and other build system maintenance, xmake defaults to using autotools by default. If you want to force switch to other build systems, you can execute:</p>
<pre><code class="lang-bash">$ xmake f --trybuild=[autotools|cmake|make|msbuild|..]
$ xmake
</code></pre>
<p>In addition, the <code>--trybuild=</code> parameter is configured to manually specify the default build system, and the subsequent build process will not prompt the user for selection.</p>
<h3 id="fastlycrosscompile">Fastly cross compile</h3>
<p>As we all know, although many projects maintained by autotools support cross-compilation, the configuration process of cross-compilation is very complicated. There are still many differences in different toolchain processing methods, and many pits will be stepped in the middle.</p>
<p>Even if you run through a toolchain&#39;s cross-compilation, if you switch to another toolchain environment, it may take a long time, and if you use xmake, you usually only need two simple commands:</p>
<p>!> At present cmake/autotools supports cross-compilation of xmake.</p>
<h4 id="crosscompileandroidplatform">Cross compile android platform</h4>
<pre><code class="lang-bash">$ xmake f -p android --trybuild=autotools [--ndk=xxx]
$ xmake
</code></pre>
<p>!> Among them, the --ndk parameter configuration is optional. If the user sets the ANDROID_NDK_HOME environment variable, or if the ndk is placed in ~/Library/Android/sdk/ndk-bundle, xmake can automatically detect it.</p>
<p>Is not it simple? If you think this is not much, then you can directly operate <code>./configure</code> to configure cross-compilation. You can see this document for comparison: [Using NDK with other compilation systems] (<a href="https://developer.android">https://developer.android</a> .com/ndk/guides/other_build_systems # autoconf)</p>
<p>To put it bluntly, you probably have to do this, you may not be able to do it once:</p>
<pre><code class="lang-bash">$ export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/$HOST_TAG
$ export AR=$TOOLCHAIN/bin/aarch64-linux-android-ar
$ export AS=$TOOLCHAIN/bin/aarch64-linux-android-as
$ export CC=$TOOLCHAIN/bin/aarch64-linux-android21-clang
$ export CXX=$TOOLCHAIN/bin/aarch64-linux-android21-clang++
$ export LD=$TOOLCHAIN/bin/aarch64-linux-android-ld
$ export RANLIB=$TOOLCHAIN/bin/aarch64-linux-android-ranlib
$ export STRIP=$TOOLCHAIN/bin/aarch64-linux-android-strip
$ ./configure --host aarch64-linux-android
$ make
</code></pre>
<p>If it is cmake, cross-compilation is not an easy task. For the android platform, this configuration is required.</p>
<pre><code class="lang-bash">$ cmake \
     -DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \
     -DANDROID_ABI=$ABI \
     -DANDROID_NATIVE_API_LEVEL=$MINSDKVERSION \
     $OTHER_ARGS
</code></pre>
<p>For the ios platform, I did not find a short-answer configuration method, but found a third-party ios toolchain configuration, which is very complicated: <a href="https://github.com/leetal/ios-cmake/blob/master/ios.toolchain.cmake">https://github.com/leetal/ios-cmake/blob/master/ios.toolchain.cmake</a></p>
<p>For mingw, it is another way. I have been tossing about the environment for a long time, which is very tossing.</p>
<p>After using xmake, whether it is cmake or autotools, cross-compilation is very simple, and the configuration method is exactly the same, streamlined and consistent.</p>
<h4 id="crosscompileiphoneosplatform">Cross compile iphoneos platform</h4>
<pre><code class="lang-bash">$ xmake f -p iphoneos --trybuild=[cmake|autotools]
$ xmake
</code></pre>
<h4 id="crosscompilemingwplatform">Cross-compile mingw platform</h4>
<pre><code class="lang-bash">$ xmake f -p mingw --trybuild=[cmake|autotools] [--mingw=xxx]
$ xmake
</code></pre>
<h4 id="usingothercrosscompilationtoolchains">Using other cross-compilation toolchains</h4>
<pre><code class="lang-bash">$ xmake f -p cross --trybuild=[cmake|autotools] --sdk=/xxxx
$ xmake
</code></pre>
<p>For more cross compilation configuration details, please refer to the document: <a href="https://xmake.io/#/guide/configuration?id=cross-compilation">Cross Compilation</a>, except for an additional <code>--trybuild=</code> parameter, all other cross-compilation configuration parameters are completely universal.</p>
<h3 id="passinguserconfigurationparameters">Passing user configuration parameters</h3>
<p>We can use <code>--tryconfigs=</code> to pass additional configuration parameters of the user to the corresponding third-party build system. For example: autotools will be passed to <code>. / Configure</code>, cmake will be passed to the<code>cmake</code> command.</p>
<pre><code class="lang-bash">$ xmake f --trybuild=autotools --tryconfigs="-enable-shared=no"
$ xmake
</code></pre>
<p>For example, the above command, pass <code>--enable-shared=no</code> to<code>./configure</code> to disable dynamic library compilation.</p>
<p>In addition, for <code>--cflags</code>,<code>--includedirs</code> and <code>--ldflags</code>, you don&#39;t need to pass<code>--tryconfigs</code>, you can pass the built-in parameters like <code>xmake config --cflags=</code> to pass through.</p>
<h3 id="examplesofcompilingotherbuildsystem">Examples of compiling other build system</h3>
<h4 id="generalcompilation">General Compilation</h4>
<p>In most cases, the compilation method after each docking system is consistent, except for the <code>--trybuild=</code> configuration parameter.</p>
<pre><code class="lang-bash">$ xmake f --trybuild=[autotools|cmake|meson|ninja|bazel|make|msbuild|xcodebuild]
$ xmake
</code></pre>
<p>!> We also need to make sure that the build tool specified by --trybuild is installed and working properly.</p>
<h4 id="buildingandroidjniprograms">Building Android jni programs</h4>
<p>If <code>jni/Android.mk</code> exists in the current project, then xmake can directly call ndk-build to build the jni library.</p>
<pre><code class="lang-bash">$ xmake f -p android --trybuild=ndkbuild [--ndk =]
$ xmake
</code></pre>
<p>We also provided <a href="https://github.com/xmake-io/xmake-gradle">xmake-gradle</a> to build jni library in gradle, you can see <a href="https://xmake.io/#/plugin/more_plugins?id=gradle-plugin-jni">Uses xmake to build JNI in Gradle</a></p>
<h2 id="automaticallygeneratexmakelua">Automatically generate xmake.lua</h2>
<p>we need not write any make-like file (xmake.lua, makefile.am, cmakelist.txt, etc.) and also build it directly.</p>
<p>It will scan all source files and generate xmake.lua automatically for building project.</p>
<p>And xmake will detect &#39;main&#39; function in source file in order to distinguish between static libraries and executable programs.</p>
<p>(Currently, only projects with single-level directory are supported)</p>
<h3 id="usedscenes">Used scenes</h3>
<ol>
<li>Temporarily quickly compile and run some scattered test code</li>
<li>Try porting and compiling other open source libraries</li>
<li>Quickly create a new xmake project based on existing code</li>
</ol>
<h3 id="howtouseit">How to use it</h3>
<p>Execute xmake directly in the directory with the source code (no xmake.lua), and follow the prompts:</p>
<pre><code class="lang-bash">$ xmake
note: xmake.lua not found, try generating it (pass -y or --confirm=y/n/d to skip confirm)?
please input: n (y/n)
y
</code></pre>
<h3 id="compileopensourcelibraries">Compile open source libraries</h3>
<p>Although this approach has some limitations, but it is sufficient to complie and run some temporary codes for testing. </p>
<p>For example, we downloaded a zlib-1.2.10 source and want to compile it.</p>
<p>We only need to enter the zlib source directory and run the following command:</p>
<pre><code class="lang-bash">$ cd zlib-1.2.10
$ xmake
note: xmake.lua not found, try generating it (pass -y or --confirm=y/n/d to skip confirm)?
please input: n (y/n)
y
</code></pre>
<p>It&#39;s done, the output results: </p>
<pre><code>target(zlib-1.2): static
    [+]: ./adler32.c
    [+]: ./compress.c
    [+]: ./crc32.c
    [+]: ./deflate.c
    [+]: ./gzclose.c
    [+]: ./gzlib.c
    [+]: ./gzread.c
    [+]: ./gzwrite.c
    [+]: ./infback.c
    [+]: ./inffast.c
    [+]: ./inflate.c
    [+]: ./inftrees.c
    [+]: ./trees.c
    [+]: ./uncompr.c
    [+]: ./zutil.c
xmake.lua generated, scan ok!👌
checking for the architecture ... x86_64
checking for the Xcode SDK version for macosx ... 10.12
checking for the target minimal version ... 10.12
checking for the c compiler (cc) ... xcrun -sdk macosx clang
checking for the c++ compiler (cxx) ... xcrun -sdk macosx clang
checking for the objc compiler (mm) ... xcrun -sdk macosx clang
checking for the objc++ compiler (mxx) ... xcrun -sdk macosx clang++
checking for the swift compiler (sc) ... xcrun -sdk macosx swiftc
checking for the assember (as) ... xcrun -sdk macosx clang
checking for the linker (ld) ... xcrun -sdk macosx clang++
checking for the static library archiver (ar) ... xcrun -sdk macosx ar
checking for the static library extractor (ex) ... xcrun -sdk macosx ar
checking for the shared library linker (sh) ... xcrun -sdk macosx clang++
checking for the debugger (dd) ... xcrun -sdk macosx lldb
checking for the golang compiler (go) ... go
configure
{
    ex = "xcrun -sdk macosx ar"
,   sh = "xcrun -sdk macosx clang++"
,   host = "macosx"
,   ar = "xcrun -sdk macosx ar"
,   buildir = "build"
,   as = "xcrun -sdk macosx clang"
,   plat = "macosx"
,   xcode_dir = "/Applications/Xcode.app"
,   arch = "x86_64"
,   mxx = "xcrun -sdk macosx clang++"
,   go = "go"
,   target_minver = "10.12"
,   ccache = "ccache"
,   mode = "release"
,   clean = true
,   cxx = "xcrun -sdk macosx clang"
,   cc = "xcrun -sdk macosx clang"
,   dd = "xcrun -sdk macosx lldb"
,   kind = "static"
,   ld = "xcrun -sdk macosx clang++"
,   xcode_sdkver = "10.12"
,   sc = "xcrun -sdk macosx swiftc"
,   mm = "xcrun -sdk macosx clang"
}
configure ok!
clean ok!
[00%]: ccache compiling.release ./adler32.c
[06%]: ccache compiling.release ./compress.c
[13%]: ccache compiling.release ./crc32.c
[20%]: ccache compiling.release ./deflate.c
[26%]: ccache compiling.release ./gzclose.c
[33%]: ccache compiling.release ./gzlib.c
[40%]: ccache compiling.release ./gzread.c
[46%]: ccache compiling.release ./gzwrite.c
[53%]: ccache compiling.release ./infback.c
[60%]: ccache compiling.release ./inffast.c
[66%]: ccache compiling.release ./inflate.c
[73%]: ccache compiling.release ./inftrees.c
[80%]: ccache compiling.release ./trees.c
[86%]: ccache compiling.release ./uncompr.c
[93%]: ccache compiling.release ./zutil.c
[100%]: archiving.release libzlib-1.2.a
build ok!👌
</code></pre><p>Xmake will scan the current directory to detect all source codes and it do not found main function.</p>
<p>So it should be static library project and we build it as a static library: libzlib-1.2.a</p>
<p>We did not write any make-like files (xmake.lua, ..) and did not use the makefile of zlib project.</p>
<p>It is compiled directly and a xmake.lua file was generated which we can edit this xmake.lua to build more complicated project. </p>
<p>The content of the generated xmake.lua:</p>
<pre><code class="lang-lua">-- define target
target("zlib-1.2")

    -- set kind
    set_kind("static")

    -- add files
    add_files("./adler32.c")
    add_files("./compress.c")
    add_files("./crc32.c")
    add_files("./deflate.c")
    add_files("./gzclose.c")
    add_files("./gzlib.c")
    add_files("./gzread.c")
    add_files("./gzwrite.c")
    add_files("./infback.c")
    add_files("./inffast.c")
    add_files("./inflate.c")
    add_files("./inftrees.c")
    add_files("./trees.c")
    add_files("./uncompr.c")
    add_files("./zutil.c")
</code></pre>
<h3 id="fastlycompileandruntestingcode">Fastly compile and run testing code</h3>
<p>For example, I want to write a simple program in the main.c only to echo &#39;hello world!&#39;.</p>
<p>If we use gcc to compile and run it, need run two commands: </p>
<pre><code class="lang-bash">gcc ./main.c -o demo
./demo
</code></pre>
<p>If we use xmake to run it, only need run:</p>
<pre><code class="lang-bash">xmake run
</code></pre>
<p>Or</p>
<pre><code class="lang-bash">xmake r
</code></pre>
<p>It&#39;s done, the output results is:</p>
<pre><code>hello world!
</code></pre><p>If we have a lot of code files, need also run only one command:</p>
<pre><code class="lang-bash">xmake run
</code></pre>
<p>It&#39;s so easy and convenient.</p>
<h3 id="multilanguagesupport">Multi-language support</h3>
<p>This feature of code detection and real-time compilation not only supports c/c++, also supports objc/swift<br>and it will support golang in future.</p>
<p>For example, we downloaded a ios open source framework code &#39;fmdb&#39;:</p>
<pre><code>.
├── FMDB.h
├── FMDatabase.h
├── FMDatabase.m
├── FMDatabaseAdditions.h
├── FMDatabaseAdditions.m
├── FMDatabasePool.h
├── FMDatabasePool.m
├── FMDatabaseQueue.h
├── FMDatabaseQueue.m
├── FMResultSet.h
└── FMResultSet.m
</code></pre><p>There are no any make-like files in it&#39;s project directory.</p>
<p>We uses xmake to build it directly as a ios static library:</p>
<pre><code class="lang-bash">$ xmake f -p iphoneos; xmake
</code></pre>
<p>The output results are:</p>
<pre><code>xmake.lua not found, scanning files ..
target(FMDB): static
    [+]: ./FMDatabase.m
    [+]: ./FMDatabaseAdditions.m
    [+]: ./FMDatabasePool.m
    [+]: ./FMDatabaseQueue.m
    [+]: ./FMResultSet.m
xmake.lua generated, scan ok!👌
checking for the architecture ... armv7
checking for the Xcode SDK version for iphoneos ... 10.1
checking for the target minimal version ... 10.1
checking for the c compiler (cc) ... xcrun -sdk iphoneos clang
checking for the c++ compiler (cxx) ... xcrun -sdk iphoneos clang
checking for the objc compiler (mm) ... xcrun -sdk iphoneos clang
checking for the objc++ compiler (mxx) ... xcrun -sdk iphoneos clang++
checking for the assember (as) ... gas-preprocessor.pl xcrun -sdk iphoneos clang
checking for the linker (ld) ... xcrun -sdk iphoneos clang++
checking for the static library archiver (ar) ... xcrun -sdk iphoneos ar
checking for the static library extractor (ex) ... xcrun -sdk iphoneos ar
checking for the shared library linker (sh) ... xcrun -sdk iphoneos clang++
checking for the swift compiler (sc) ... xcrun -sdk iphoneos swiftc
configure
{
    ex = "xcrun -sdk iphoneos ar"
,   ccache = "ccache"
,   host = "macosx"
,   ar = "xcrun -sdk iphoneos ar"
,   buildir = "build"
,   as = "/usr/local/share/xmake/tools/utils/gas-preprocessor.pl xcrun -sdk iphoneos clang"
,   arch = "armv7"
,   mxx = "xcrun -sdk iphoneos clang++"
,   cxx = "xcrun -sdk iphoneos clang"
,   target_minver = "10.1"
,   xcode_dir = "/Applications/Xcode.app"
,   clean = true
,   sh = "xcrun -sdk iphoneos clang++"
,   cc = "xcrun -sdk iphoneos clang"
,   ld = "xcrun -sdk iphoneos clang++"
,   mode = "release"
,   kind = "static"
,   plat = "iphoneos"
,   xcode_sdkver = "10.1"
,   sc = "xcrun -sdk iphoneos swiftc"
,   mm = "xcrun -sdk iphoneos clang"
}
configure ok!
clean ok!
[00%]: ccache compiling.release ./FMDatabase.m
[20%]: ccache compiling.release ./FMDatabaseAdditions.m
[40%]: ccache compiling.release ./FMDatabasePool.m
[60%]: ccache compiling.release ./FMDatabaseQueue.m
[80%]: ccache compiling.release ./FMResultSet.m
[100%]: archiving.release libFMDB.a
build ok!👌
</code></pre><h3 id="compilemultipleexecutablesatthesametime">Compile multiple executables at the same time</h3>
<pre><code class="lang-bash">$ cd jpeg-6b
$ xmake
</code></pre>
<p>The output results are:</p>
<pre><code>xmake.lua not found, scanning files ..
target(jpeg-6b): static
    [+]: ./cdjpeg.c
    [+]: ./example.c
    [+]: ./jcapimin.c
    [+]: ./jcapistd.c
    [+]: ./jccoefct.c
    [+]: ./jccolor.c
    [+]: ./jcdctmgr.c
    [+]: ./jchuff.c
    [+]: ./jcinit.c
    [+]: ./jcmainct.c
    [+]: ./jcmarker.c
    [+]: ./jcmaster.c
    [+]: ./jcomapi.c
    [+]: ./jcparam.c
    [+]: ./jcphuff.c
    [+]: ./jcprepct.c
    [+]: ./jcsample.c
    [+]: ./jctrans.c
    [+]: ./jdapimin.c
    [+]: ./jdapistd.c
    [+]: ./jdatadst.c
    [+]: ./jdatasrc.c
    [+]: ./jdcoefct.c
    [+]: ./jdcolor.c
    [+]: ./jddctmgr.c
    [+]: ./jdhuff.c
    [+]: ./jdinput.c
    [+]: ./jdmainct.c
    [+]: ./jdmarker.c
    [+]: ./jdmaster.c
    [+]: ./jdmerge.c
    [+]: ./jdphuff.c
    [+]: ./jdpostct.c
    [+]: ./jdsample.c
    [+]: ./jdtrans.c
    [+]: ./jerror.c
    [+]: ./jfdctflt.c
    [+]: ./jfdctfst.c
    [+]: ./jfdctint.c
    [+]: ./jidctflt.c
    [+]: ./jidctfst.c
    [+]: ./jidctint.c
    [+]: ./jidctred.c
    [+]: ./jmemansi.c
    [+]: ./jmemmgr.c
    [+]: ./jmemname.c
    [+]: ./jmemnobs.c
    [+]: ./jquant1.c
    [+]: ./jquant2.c
    [+]: ./jutils.c
    [+]: ./rdbmp.c
    [+]: ./rdcolmap.c
    [+]: ./rdgif.c
    [+]: ./rdppm.c
    [+]: ./rdrle.c
    [+]: ./rdswitch.c
    [+]: ./rdtarga.c
    [+]: ./transupp.c
    [+]: ./wrbmp.c
    [+]: ./wrgif.c
    [+]: ./wrppm.c
    [+]: ./wrrle.c
    [+]: ./wrtarga.c
target(ansi2knr): binary
    [+]: ./ansi2knr.c
target(cjpeg): binary
    [+]: ./cjpeg.c
target(ckconfig): binary
    [+]: ./ckconfig.c
target(djpeg): binary
    [+]: ./djpeg.c
target(jpegtran): binary
    [+]: ./jpegtran.c
target(rdjpgcom): binary
    [+]: ./rdjpgcom.c
target(wrjpgcom): binary
    [+]: ./wrjpgcom.c
xmake.lua generated, scan ok!👌
checking for the architecture ... x86_64
checking for the Xcode SDK version for macosx ... 10.12
checking for the target minimal version ... 10.12
checking for the c compiler (cc) ... xcrun -sdk macosx clang
checking for the c++ compiler (cxx) ... xcrun -sdk macosx clang
checking for the objc compiler (mm) ... xcrun -sdk macosx clang
checking for the objc++ compiler (mxx) ... xcrun -sdk macosx clang++
checking for the swift compiler (sc) ... xcrun -sdk macosx swiftc
checking for the assember (as) ... xcrun -sdk macosx clang
checking for the linker (ld) ... xcrun -sdk macosx clang++
checking for the static library archiver (ar) ... xcrun -sdk macosx ar
checking for the static library extractor (ex) ... xcrun -sdk macosx ar
checking for the shared library linker (sh) ... xcrun -sdk macosx clang++
checking for the debugger (dd) ... xcrun -sdk macosx lldb
checking for the golang compiler (go) ... go
configure
{
    ex = "xcrun -sdk macosx ar"
,   sh = "xcrun -sdk macosx clang++"
,   host = "macosx"
,   ar = "xcrun -sdk macosx ar"
,   buildir = "build"
,   as = "xcrun -sdk macosx clang"
,   plat = "macosx"
,   xcode_dir = "/Applications/Xcode.app"
,   arch = "x86_64"
,   mxx = "xcrun -sdk macosx clang++"
,   go = "go"
,   target_minver = "10.12"
,   ccache = "ccache"
,   mode = "release"
,   clean = true
,   cxx = "xcrun -sdk macosx clang"
,   cc = "xcrun -sdk macosx clang"
,   dd = "xcrun -sdk macosx lldb"
,   kind = "static"
,   ld = "xcrun -sdk macosx clang++"
,   xcode_sdkver = "10.12"
,   sc = "xcrun -sdk macosx swiftc"
,   mm = "xcrun -sdk macosx clang"
}
configure ok!
clean ok!
[00%]: ccache compiling.release ./cdjpeg.c
[00%]: ccache compiling.release ./example.c
[00%]: ccache compiling.release ./jcapimin.c
[00%]: ccache compiling.release ./jcapistd.c
[00%]: ccache compiling.release ./jccoefct.c
[00%]: ccache compiling.release ./jccolor.c
[01%]: ccache compiling.release ./jcdctmgr.c
[01%]: ccache compiling.release ./jchuff.c
[01%]: ccache compiling.release ./jcinit.c
[01%]: ccache compiling.release ./jcmainct.c
[01%]: ccache compiling.release ./jcmarker.c
[02%]: ccache compiling.release ./jcmaster.c
[02%]: ccache compiling.release ./jcomapi.c
[02%]: ccache compiling.release ./jcparam.c
[02%]: ccache compiling.release ./jcphuff.c
[02%]: ccache compiling.release ./jcprepct.c
[03%]: ccache compiling.release ./jcsample.c
[03%]: ccache compiling.release ./jctrans.c
[03%]: ccache compiling.release ./jdapimin.c
[03%]: ccache compiling.release ./jdapistd.c
[03%]: ccache compiling.release ./jdatadst.c
[04%]: ccache compiling.release ./jdatasrc.c
[04%]: ccache compiling.release ./jdcoefct.c
[04%]: ccache compiling.release ./jdcolor.c
[04%]: ccache compiling.release ./jddctmgr.c
[04%]: ccache compiling.release ./jdhuff.c
[05%]: ccache compiling.release ./jdinput.c
[05%]: ccache compiling.release ./jdmainct.c
[05%]: ccache compiling.release ./jdmarker.c
[05%]: ccache compiling.release ./jdmaster.c
[05%]: ccache compiling.release ./jdmerge.c
[06%]: ccache compiling.release ./jdphuff.c
[06%]: ccache compiling.release ./jdpostct.c
[06%]: ccache compiling.release ./jdsample.c
[06%]: ccache compiling.release ./jdtrans.c
[06%]: ccache compiling.release ./jerror.c
[07%]: ccache compiling.release ./jfdctflt.c
[07%]: ccache compiling.release ./jfdctfst.c
[07%]: ccache compiling.release ./jfdctint.c
[07%]: ccache compiling.release ./jidctflt.c
[07%]: ccache compiling.release ./jidctfst.c
[08%]: ccache compiling.release ./jidctint.c
[08%]: ccache compiling.release ./jidctred.c
[08%]: ccache compiling.release ./jmemansi.c
[08%]: ccache compiling.release ./jmemmgr.c
[08%]: ccache compiling.release ./jmemname.c
[09%]: ccache compiling.release ./jmemnobs.c
[09%]: ccache compiling.release ./jquant1.c
[09%]: ccache compiling.release ./jquant2.c
[09%]: ccache compiling.release ./jutils.c
[09%]: ccache compiling.release ./rdbmp.c
[10%]: ccache compiling.release ./rdcolmap.c
[10%]: ccache compiling.release ./rdgif.c
[10%]: ccache compiling.release ./rdppm.c
[10%]: ccache compiling.release ./rdrle.c
[10%]: ccache compiling.release ./rdswitch.c
[11%]: ccache compiling.release ./rdtarga.c
[11%]: ccache compiling.release ./transupp.c
[11%]: ccache compiling.release ./wrbmp.c
[11%]: ccache compiling.release ./wrgif.c
[11%]: ccache compiling.release ./wrppm.c
[12%]: ccache compiling.release ./wrrle.c
[12%]: ccache compiling.release ./wrtarga.c
[12%]: archiving.release libjpeg-6b.a
[12%]: ccache compiling.release ./wrjpgcom.c
[25%]: linking.release wrjpgcom
[25%]: ccache compiling.release ./ansi2knr.c
[37%]: linking.release ansi2knr
[37%]: ccache compiling.release ./jpegtran.c
[50%]: linking.release jpegtran
[50%]: ccache compiling.release ./djpeg.c
[62%]: linking.release djpeg
[62%]: ccache compiling.release ./ckconfig.c
[75%]: linking.release ckconfig
[75%]: ccache compiling.release ./rdjpgcom.c
[87%]: linking.release rdjpgcom
[87%]: ccache compiling.release ./cjpeg.c
[100%]: linking.release cjpeg
build ok!👌
</code></pre><p>In addition to a static library, we also compiled some other executable programs.</p>
<pre><code>target(ansi2knr): binary
    [+]: ./ansi2knr.c
target(cjpeg): binary
    [+]: ./cjpeg.c
target(ckconfig): binary
    [+]: ./ckconfig.c
target(djpeg): binary
    [+]: ./djpeg.c
target(jpegtran): binary
    [+]: ./jpegtran.c
target(rdjpgcom): binary
    [+]: ./rdjpgcom.c
target(wrjpgcom): binary
    [+]: ./wrjpgcom.c
</code></pre><h4 id="manualconfiguration">Manual configuration</h4>
<p>we need add them before compiling if the source code requires some special compiler options</p>
<p>For example:</p>
<pre><code class="lang-bash">$ xmake f --cxflags="" --ldflags="" --includedirs="" --linkdirs=""; xmake
</code></pre>
<h2 id="unitybuildcompilationacceleration">Unity Build compilation acceleration</h2>
<p>We know that C++ code compilation speed is usually very slow, because each code file needs to parse the imported header file.</p>
<p>With Unity Build, we accelerate the compilation of the project by combining multiple cpp files into one. The main benefit is to reduce the repetitive work of parsing and compiling the contents of the header files contained in multiple source files. The contents of the header files are usually It accounts for most of the code in the source file after preprocessing.</p>
<p>Unity build also reduces the overhead caused by having a large number of small source files by reducing the number of object files created and processed by the compilation chain, and allows inter-procedural analysis and optimization across files that form a unified build task (similar to optimization during effect linking ).</p>
<p>It can greatly improve the compilation speed of C/C++ code, usually by 30%. However, depending on the complexity of the project, the benefits it brings depend on the situation of the project.</p>
<p>xmake has also supported this build mode in v2.5.9. For related issues, see <a href="https://github.com/xmake-io/xmake/issues/1019">#1019</a>.</p>
<h3 id="howtoenableit">How to enable it?</h3>
<p>We provide two built-in rules to handle Unity Build for C and C++ code respectively.</p>
<pre><code class="lang-lua">add_rules("c.unity_build")
add_rules("c++.unity_build")
</code></pre>
<h3 id="batchmode">Batch mode</h3>
<p>By default, as long as the above rules are set, Unity Build in Batch mode will be enabled, that is, xmake will automatically organize and merge according to the project code files.</p>
<pre><code class="lang-lua">target("test")
    set_kind("binary")
    add_includedirs("src")
    add_rules("c++.unity_build", {batchsize = 2})
    add_files("src/*.c", "src/*.cpp")
</code></pre>
<p>We can additionally specify the size of each merged Batch by setting the <code>{batchsize = 2}</code> parameter to the rule, which means that every two C++ files are automatically merged and compiled.</p>
<p>The compilation effect is roughly as follows:</p>
<pre><code class="lang-console">$ xmake -r
[11%]: ccache compiling.release build/.gens/test/unity_build/unity_642A245F.cpp
[11%]: ccache compiling.release build/.gens/test/unity_build/unity_bar.cpp
[11%]: ccache compiling.release build/.gens/test/unity_build/unity_73161A20.cpp
[11%]: ccache compiling.release build/.gens/test/unity_build/unity_F905F036.cpp
[11%]: ccache compiling.release build/.gens/test/unity_build/unity_foo.cpp
[11%]: ccache compiling.release build/.gens/test/unity_build/main.c
[77%]: linking.release test
[100%]: build ok
</code></pre>
<p>Since we only enabled the Unity Build of C++, the C code is still compiled one by one normally. In addition, in the Unity Build mode, we can still speed up the parallel compilation as much as possible without conflicting each other.</p>
<p>If the <code>batchsize</code> parameter is not set, all files will be merged into one file for compilation by default.</p>
<h3 id="groupmode">Group Mode</h3>
<p>If the automatic merging effect of the above Batch mode is not satisfactory, we can also use custom grouping to manually configure which files are merged together to participate in the compilation, which makes users more flexible and controllable.</p>
<pre><code class="lang-lua">target("test")
    set_kind("binary")
    add_rules("c++.unity_build", {batchsize = 0}) - disable batch mode
    add_files("src/*.c", "src/*.cpp")
    add_files("src/foo/*.c", {unity_group = "foo"})
    add_files("src/bar/*.c", {unity_group = "bar"})
</code></pre>
<p>We use <code>{unity_group = "foo"}</code> to specify the name of each group and which files are included. The files in each group will be merged into one code file separately.</p>
<p>In addition, <code>batchsize = 0</code> also forcibly disables the Batch mode, that is, if there is no unity_group grouped code files, we will still compile them separately, and will not automatically turn on automatic merging.</p>
<h3 id="batchandgroupmixedmode">Batch and Group mixed mode</h3>
<p>As long as we change the above <code>batchsize = 0</code> to a value other than 0, we can let the remaining code files continue to open the Batch mode in the grouping mode to automatically merge and compile.</p>
<pre><code class="lang-lua">target("test")
    set_kind("binary")
    add_includedirs("src")
    add_rules("c++.unity_build", {batchsize = 2})
    add_files("src/*.c", "src/*.cpp")
    add_files("src/foo/*.c", {unity_group = "foo"})
    add_files("src/bar/*.c", {unity_group = "bar"})
</code></pre>
<h3 id="ignorethespecifiedfile">Ignore the specified file</h3>
<p>If it is in Batch mode, because it is an automatic merge operation, all files will be merged by default, but if some code files do not want to participate in the merge, then we can also ignore them through <code>{unity_ignored = true}</code>.</p>
<pre><code class="lang-lua">target("test")
    set_kind("binary")
    add_includedirs("src")
    add_rules("c++.unity_build", {batchsize = 2})
    add_files("src/*.c", "src/*.cpp")
    add_files("src/test/*.c", {unity_ignored = true}) - ignore these files
</code></pre>
<h3 id="uniqueid">Unique ID</h3>
<p>Although the benefits of Unity Build are good, we still encounter some unexpected situations. For example, in our two code files, under the global namespace, there are global variables and functions with the same name.</p>
<p>Then, merge compilation will bring about compilation conflicts, and the compiler usually reports global variable redefinition errors.</p>
<p>In order to solve this problem, we need to make some modifications to the user code, and then cooperate with the build tool to solve it.</p>
<p>For example, our foo.cpp and bar.cpp both have global variable i.</p>
<p>foo.cpp</p>
<pre><code class="lang-c">namespace {
    int i = 42;
}

int foo()
{
    return i;
}
</code></pre>
<p>bar.cpp</p>
<pre><code class="lang-c">namespace {
    int i = 42;
}

int bar()
{
    return i;
}
</code></pre>
<p>Then, our merge compilation will conflict, and we can introduce a Unique ID to isolate the global anonymous space.</p>
<p>foo.cpp</p>
<pre><code class="lang-c">namespace MY_UNITY_ID {
    int i = 42;
}

int foo()
{
    return MY_UNITY_ID::i;
}
</code></pre>
<p>bar.cpp</p>
<pre><code class="lang-c">namespace MY_UNITY_ID {
    int i = 42;
}

int bar()
{
    return MY_UNITY_ID::i;
}
</code></pre>
<p>Next, we also need to ensure that after the code is merged, the definitions of <code>MY_UNITY_ID</code> in foo and bar are completely different, and a unique ID value can be calculated according to the file name, which does not conflict with each other, which is to achieve the following merge effect:</p>
<pre><code class="lang-c">#define MY_UNITY_ID <hash(foo.cpp)>
#include "foo.c"
#undef MY_UNITY_ID
#define MY_UNITY_ID <hash(bar.cpp)>
#include "bar.c"
#undef MY_UNITY_ID
</code></pre>
<p>This may seem troublesome, but the user does not need to care about these, xmake will automatically process them when merging, the user only needs to specify the name of the Unique ID, for example, the following:</p>
<pre><code class="lang-lua">target("test")
    set_kind("binary")
    add_includedirs("src")
    add_rules("c++.unity_build", {batchsize = 2, uniqueid = "MY_UNITY_ID"})
    add_files("src/*.c", "src/*.cpp")
</code></pre>
<p>Dealing with global variables, as well as global macro definitions with the same name, functions, etc., can be used in this way to avoid conflicts.</p>
</article>
</body>
</html>